home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #1 / Amiga Plus CD - 2000 - No. 1.iso / Tools / HD / SmartFileSystem / V1.58 / Sources / SFScheck / SFScheck.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-04  |  29.5 KB  |  1,117 lines

  1. #include <clib/macros.h>
  2. #include <devices/scsidisk.h>
  3. #include <devices/trackdisk.h>
  4. #include <dos/dos.h>
  5. #include <dos/dosextens.h>
  6. #include <dos/filehandler.h>
  7. #include <exec/errors.h>
  8. #include <exec/io.h>
  9. #include <exec/memory.h>
  10. #include <proto/dos.h>
  11. #include <proto/exec.h>
  12. #include <proto/intuition.h>
  13. #include <string.h>
  14. #include "stdio.h"
  15.  
  16. #include "/fs/deviceio.h"
  17. #include "/fs/deviceio_protos.h"
  18. #include "/fs/cachedio_protos.h"
  19.  
  20.  
  21. #include "/fs/adminspaces.h"
  22. #include "/fs/bitmap.h"
  23. #include "/fs/objects.h"
  24. #include "/fs/transactions.h"
  25. #include "/fs/fs.h"
  26. #include "/fs/btreenodes.h"
  27.  
  28. #include "/bitfuncs.c"
  29.  
  30.  
  31. #define BLCKFACCURACY   (5)                          /* 2^5 = 32 */
  32.  
  33.  
  34. /* ASM prototypes */
  35.  
  36. extern ULONG __asm RANDOM(register __d0 ULONG);
  37. extern LONG __asm STACKSWAP(void);
  38. extern ULONG __asm CALCCHECKSUM(register __d0 ULONG,register __a0 ULONG *);
  39. extern ULONG __asm MULU64(register __d0 ULONG,register __d1 ULONG,register __a0 ULONG *);
  40. extern WORD __asm COMPRESSFROMZERO(register __a0 UWORD *,register __a1 UBYTE *,register __d0 ULONG);
  41.  
  42.  
  43. static const char version[]={"\0$VER: SFScheck 1.2 " __AMIGADATE__ "\r\n"};
  44.  
  45.  
  46. LONG read2(ULONG block);
  47. void sfscheck(void);
  48. BOOL iszero(void *a,LONG size);
  49. BOOL isblockvalid(void *b, ULONG block, ULONG id);
  50. LONG findbnode(BLCK rootblock,ULONG key,struct BNode **returned_bnode);
  51. UBYTE *mark(LONG offset, LONG blocks);
  52. BOOL error(UBYTE *fmt, ... );
  53. void freestring(UBYTE *str);
  54. UBYTE *tostring(UBYTE *fmt, ... );
  55.  
  56. ULONG errors=0;
  57. ULONG maxerrors=10;
  58. UBYTE emptystring[]="";
  59.  
  60. UBYTE string[200];
  61.  
  62. struct DosEnvec *dosenvec;
  63.  
  64. /* blocks_  = the number of blocks of something (blocks can contain 1 or more sectors)
  65.    block_   = a block number of something (relative to start of partition)
  66.    sectors_ = the number of sectors of something (1 or more sectors form a logical block)
  67.    sector_  = a sector number (relative to the start of the disk)
  68.    bytes_   = the number of bytes of something
  69.    byte_    = a byte number of something
  70.    shifts_  = the number of bytes written as 2^x of something
  71.    mask_    = a mask for something */
  72.  
  73. extern ULONG blocks_total;               /* size of the partition in blocks */
  74. ULONG blocks_reserved_start;      /* number of blocks reserved at start (=reserved) */
  75. ULONG blocks_reserved_end;        /* number of blocks reserved at end (=prealloc) */
  76. ULONG blocks_bitmap;              /* number of BTMP blocks for this partition */
  77. ULONG blocks_inbitmap;            /* number of blocks a single bitmap block can contain info on */
  78. ULONG blocks_admin;               /* the size of all AdminSpaces */
  79.  
  80. ULONG block_root;                 /* the block offset of the root block */
  81. ULONG block_bitmapbase;           /* the block offset of the first bitmap block */
  82. ULONG block_extentbnoderoot;      /* the block offset of the root of the extent bnode tree */
  83. ULONG block_adminspace;           /* the block offset of the first adminspacecontainer block */
  84. ULONG block_rovingblockptr;       /* the roving block pointer! */
  85. ULONG block_objectnodesbase;
  86.  
  87. extern ULONG byte_low;                   /* the byte offset of our partition on the disk */
  88. extern ULONG byte_lowh;                  /* high 32 bits */
  89. extern ULONG byte_high;                  /* the byte offset of the end of our partition (excluding) on the disk */
  90. extern ULONG byte_highh;                 /* high 32 bits */
  91.  
  92. ULONG node_containers;            /* number of containers per ExtentIndexContainer */
  93.  
  94. extern ULONG bytes_block;                /* size of a block in bytes */
  95.  
  96. ULONG mask_block32;               /* masks the least significant bits of a BLCKf pointer */
  97.  
  98. extern UWORD shifts_block;               /* shift count needed to convert a blockoffset<->byteoffset */
  99. UWORD shifts_block32;             /* shift count needed to convert a blockoffset<->32byteoffset (only used by nodes.c!) */
  100.  
  101. extern ULONG bufmemtype;
  102.  
  103. void *pool;
  104.  
  105. UBYTE *buffer;
  106. ULONG *bitmap;
  107.  
  108. ULONG returncode=0;
  109.  
  110. LONG main() {
  111.   struct RDArgs *readarg;
  112.   UBYTE template[]="DEVICE=DRIVE/A,LOCK/S\n";
  113.  
  114.   struct {char *device;
  115.           ULONG lock;} arglist={NULL};
  116.  
  117.   if((DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",39))!=0) {
  118.     if((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",39))!=0) {
  119.       if((pool=CreatePool(0,16384,8192))!=0) {
  120.         if((readarg=ReadArgs(template,(LONG *)&arglist,0))!=0) {
  121.           struct DosList *dl;
  122.           UBYTE *devname=arglist.device;
  123.  
  124.           while(*devname!=0) {
  125.             if(*devname==':') {
  126.               *devname=0;
  127.               break;
  128.             }
  129.             devname++;
  130.           }
  131.  
  132.           dl=LockDosList(LDF_DEVICES|LDF_READ);
  133.           if((dl=FindDosEntry(dl,arglist.device,LDF_DEVICES))!=0) {
  134.             struct FileSysStartupMsg *fssm;
  135.             struct MsgPort *msgport;
  136.             LONG errorcode;
  137.  
  138.             fssm=(struct FileSysStartupMsg *)BADDR(dl->dol_misc.dol_handler.dol_Startup);
  139.             dosenvec=(struct DosEnvec *)BADDR(fssm->fssm_Environ);
  140.             msgport=dl->dol_Task;
  141.  
  142.             UnLockDosList(LDF_DEVICES|LDF_READ);
  143.  
  144.             if(arglist.lock==0 || (errorcode=DoPkt(msgport, ACTION_INHIBIT, DOSTRUE, 0, 0, 0, 0))!=DOSFALSE) {
  145.  
  146.               if((initcachedio((UBYTE *)BADDR(fssm->fssm_Device)+1, fssm->fssm_Unit, fssm->fssm_Flags, dosenvec))==0) {
  147.  
  148.                 setiocache(128, 8192, FALSE);     /* 1 MB for read-ahead cache, no copyback mode. */
  149.  
  150.                 shifts_block32=shifts_block-BLCKFACCURACY;
  151.  
  152.                 mask_block32=(1<<shifts_block32)-1;
  153.  
  154.                 blocks_reserved_start=MAX(dosenvec->de_Reserved,1);
  155.                 blocks_reserved_end=MAX(dosenvec->de_PreAlloc,1);
  156.  
  157.                 blocks_inbitmap=(bytes_block-sizeof(struct fsBitmap))<<3;  /* must be a multiple of 32 !! */
  158.                 blocks_bitmap=(blocks_total+blocks_inbitmap-1)/blocks_inbitmap;
  159.                 blocks_admin=32;
  160.  
  161.                 printf("Partition start offset : 0x%08lx:%08lx   End offset : 0x%08lx:%08lx\n",byte_lowh, byte_low, byte_highh, byte_high);
  162.                 printf("Surfaces         : %-5ld   Blocks/Track  : %ld\n", dosenvec->de_Surfaces, dosenvec->de_BlocksPerTrack);
  163.                 printf("Bytes/Block      : %-5ld   Sectors/Block : %ld\n", bytes_block, dosenvec->de_SectorPerBlock);
  164.                 printf("Total blocks     : %ld\n", blocks_total);
  165.                 printf("Device interface : ");
  166.  
  167.                 switch(deviceapiused()) {
  168.                 case DAU_NSD:
  169.                   printf("NSD (64-bit)\n");
  170.                   break;
  171.                 case DAU_TD64:
  172.                   printf("TD64\n");
  173.                   break;
  174.                 case DAU_SCSIDIRECT:
  175.                   printf("SCSI direct\n");
  176.                   break;
  177.                 default:
  178.                   printf("(standard)\n");
  179.                   break;
  180.                 }
  181.  
  182.                 if((buffer=AllocVec(bytes_block, bufmemtype))!=0) {
  183.                   if((bitmap=AllocVec(((blocks_total+31)>>5)<<3,MEMF_CLEAR))!=0) {
  184.                     UBYTE *str;
  185.  
  186.                     bitmap[blocks_total>>5]=0xFFFFFFFF>>(blocks_total & 0x0000001F);
  187.                     if((str=mark(0,blocks_reserved_start))!=0) {
  188.                       printf("Error while marking reserved blocks at start:\n%s",str);
  189.                       freestring(str);
  190.                     }
  191.                     if((str=mark(blocks_total-blocks_reserved_end,blocks_reserved_end))!=0) {
  192.                       printf("Error while marking reserved blocks at end:\n%s",str);
  193.                       freestring(str);
  194.                     }
  195.  
  196.                     sfscheck();
  197.  
  198.                     FreeVec(bitmap);
  199.                   }
  200.                   else {
  201.                     printf("Not enough memory\n");
  202.                   }
  203.                   FreeVec(buffer);
  204.                 }
  205.                 else {
  206.                   printf("Not enough memory\n");
  207.                 }
  208.  
  209.                 cleanupcachedio();
  210.               }
  211.  
  212.               if(arglist.lock!=0) {
  213.                 DoPkt(msgport,ACTION_INHIBIT,DOSFALSE,0,0,0,0);
  214.               }
  215.             }
  216.             else {
  217.               PrintFault(errorcode, "error while locking the drive");
  218.             }
  219.           }
  220.           else {
  221.             VPrintf("Unknown device %s\n",&arglist.device);
  222.             UnLockDosList(LDF_DEVICES|LDF_READ);
  223.           }
  224.  
  225.           FreeArgs(readarg);
  226.         }
  227.         DeletePool(pool);
  228.       }
  229.       CloseLibrary((struct Library *)IntuitionBase);
  230.     }
  231.     CloseLibrary((struct Library *)DOSBase);
  232.   }
  233.   return(returncode);
  234. }
  235.  
  236.  
  237.  
  238. /*
  239.             else if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
  240.               PutStr("\n***Break\n");
  241.               break;
  242.             }
  243. */
  244.  
  245.  
  246. BOOL validblock(ULONG block) {
  247.   if(block<blocks_total) {
  248.     return(TRUE);
  249.   }
  250.   return(FALSE);
  251. }
  252.  
  253.  
  254.  
  255. LONG read2(ULONG block) {
  256. //  return(transfer(DIO_READ, buffer, block, 1));
  257.   return(read(block, buffer, 1));
  258. }
  259.  
  260.  
  261.  
  262. BOOL checkchecksum(void *d) {
  263.   ULONG *data=(ULONG *)d;
  264.  
  265.   if(CALCCHECKSUM(bytes_block,data)==0) {
  266.     return(TRUE);
  267.   }
  268.   return(FALSE);
  269. }
  270.  
  271.  
  272.  
  273. BOOL checkobjectcontainerblock(struct fsObjectContainer *b, ULONG block) {
  274.   if(isblockvalid(b,block,OBJECTCONTAINER_ID)!=FALSE) {
  275.  
  276.   }
  277.  
  278.   return(FALSE);
  279. }
  280.  
  281.  
  282.  
  283. BOOL checkbitmapblock(struct fsBitmap *b, ULONG block, ULONG sequencenumber) {
  284.   if(isblockvalid(b,block,BITMAP_ID)!=FALSE) {
  285.     ULONG l=(sequencenumber-1)*(blocks_inbitmap>>5);
  286.     WORD n=blocks_inbitmap>>5;
  287.     ULONG *bm=b->bitmap;
  288.  
  289.     if(sequencenumber==blocks_bitmap) {
  290.       n=((blocks_total - ((blocks_bitmap-1) * blocks_inbitmap))+31)>>5;
  291.     }
  292.  
  293.     while(--n>=0 && ~bitmap[l++]==*bm++) {
  294.     }
  295.  
  296.  
  297.     if(n<0) {
  298.       if(sequencenumber==blocks_bitmap) {
  299.         if((bmffo(b->bitmap, blocks_inbitmap>>5, blocks_total - ((blocks_bitmap-1) * blocks_inbitmap) ))==-1) {
  300.           return(TRUE);
  301.         }
  302.         else {
  303.           printf("Last bitmap block wasn't correctly filled out with 0's\n");
  304.         }
  305.       }
  306.       else {
  307.         return(TRUE);
  308.       }
  309.     }
  310.     else {
  311.     printf("%ld %08lx ==  %08lx\n",n,~bitmap[--l],*--bm);
  312.       printf("Bitmap block %ld contents is incorrect!\n",block);
  313.       return(TRUE);
  314.     }
  315.   }
  316.  
  317.   return(FALSE);
  318. }
  319.  
  320.  
  321.  
  322. BOOL checkbitmap(ULONG block) {
  323.   LONG n;
  324.  
  325.   for(n=1; n<=blocks_bitmap; n++) {
  326.     read2(block);
  327.     if(checkbitmapblock((struct fsBitmap *)buffer, block, n)==FALSE) {
  328.       printf("...error in bitmap block at block %ld\n",block);
  329.       return(FALSE);
  330.     }
  331.     block++;
  332.   }
  333.  
  334.   return(TRUE);
  335. }
  336.  
  337.  
  338.  
  339. BOOL checkrootblock(struct fsRootBlock *b, ULONG block) {
  340.   if(isblockvalid(b,block,DOSTYPE_ID)!=FALSE) {
  341.     if(b->version==STRUCTURE_VERSION) {
  342.       if(b->pad1==0 && b->pad2==0 && iszero(b->reserved1,8) && iszero(b->reserved2,8) && iszero(b->reserved3,32) && iszero(b->reserved4,16) && iszero((UBYTE *)b+sizeof(struct fsRootBlock),bytes_block-sizeof(struct fsRootBlock))) {
  343.         if(b->totalblocks==blocks_total) {
  344.           if(b->blocksize==bytes_block) {
  345.             return(TRUE);
  346.           }
  347.           else {
  348.             printf("RootBlock's blocksize field is %ld, while it should be %ld.\n",b->blocksize,bytes_block);
  349.           }
  350.         }
  351.         else {
  352.           printf("RootBlock's total number of blocks is %ld, while it should be %ld.\n",b->totalblocks,blocks_total);
  353.         }
  354.       }
  355.       else {
  356.         printf("Reserved areas in RootBlock weren't all set to zero.\n");
  357.       }
  358.     }
  359.     else {
  360.       printf("RootBlock's version is unsupported by this version of SFScheck\n");
  361.     }
  362.   }
  363.  
  364.   return(FALSE);
  365. }
  366.  
  367.  
  368.  
  369. BOOL isblockvalid(void *bh, ULONG block, ULONG id) {
  370.   struct fsBlockHeader *b=(struct fsBlockHeader *)bh;
  371.  
  372.   if(checkchecksum((UBYTE *)b)!=FALSE) {
  373.     if(b->id==id) {
  374.       if(b->ownblock==block) {
  375.         return(TRUE);
  376.       }
  377.       else {
  378.         printf("Location of block is invalid.\n");
  379.       }
  380.     }
  381.     else {
  382.       printf("Incorrect block type at block %ld.  Expected was 0x%08lx but it was 0x%08lx.\n",block,id,b->id);
  383.     }
  384.   }
  385.   else {
  386.     printf("Checksum failure.\n");
  387.   }
  388.  
  389.   return(FALSE);
  390. }
  391.  
  392.  
  393.  
  394. BOOL iszero(void *a,LONG size) {
  395.   UBYTE *adr=(UBYTE *)a;
  396.  
  397.   while(--size>=0 && *adr++==0) {
  398.   }
  399.  
  400.   if(size>=0) {
  401.     return(FALSE);
  402.   }
  403.   return(TRUE);
  404. }
  405.  
  406.  
  407.  
  408. struct fsObject *nextobject(struct fsObject *o) {
  409.   UBYTE *p;
  410.  
  411.   /* skips the passed in fsObject and gives a pointer back to the place where
  412.      a next fsObject structure could be located */
  413.  
  414.   p=(UBYTE *)&o->name[0];
  415.  
  416.   /* skip the filename */
  417.   while(*p++!=0) {
  418.   }
  419.  
  420.   /* skip the comment */
  421.   while(*p++!=0) {
  422.   }
  423.  
  424.   /* ensure WORD boundary */
  425.   if((((ULONG)p) & 0x01)!=0) {
  426.     p++;
  427.   }
  428.  
  429.   return((struct fsObject *)p);
  430. }
  431.  
  432.  
  433.  
  434. WORD isobject(struct fsObject *o, struct fsObjectContainer *oc) {
  435.   UBYTE *endadr;
  436.  
  437.   endadr=(UBYTE *)oc+bytes_block-sizeof(struct fsObject)-2;
  438.  
  439.   if((UBYTE *)o<endadr && o->name[0]!=0) {
  440.     return(TRUE);
  441.   }
  442.   return(FALSE);
  443. }
  444.  
  445.  
  446.  
  447. BOOL checkobjectcontainerfornode(ULONG block, ULONG node) {
  448.   struct fsObjectContainer *oc=(struct fsObjectContainer *)buffer;
  449.  
  450.   read2(block);
  451.  
  452.   if(isblockvalid(oc,block,OBJECTCONTAINER_ID)!=FALSE) {
  453.     struct fsObject *o=oc->object;
  454.  
  455.     while(isobject(o,oc)!=FALSE) {
  456.       if(o->objectnode==node) {
  457.         return(TRUE);
  458.       }
  459.  
  460.       o=nextobject(o);
  461.     }
  462.  
  463.     printf("ObjectContainer at block %ld doesn't contain node %ld\n",block,node);
  464.     return(FALSE);
  465.   }
  466.  
  467.   printf("ObjectContainer at block %ld is invalid and doesn't contain node %ld\n",block,node);
  468.   return(FALSE);
  469. }
  470.  
  471.  
  472.  
  473. BOOL checknodecontainers2(ULONG block, ULONG parent, ULONG nodenumber, ULONG nodes) {
  474.   struct fsNodeContainer *b;
  475.  
  476. //  printf("Checking NodeContainer at block %ld, with parent %ld, nodenumber %ld and nodes %ld\n",block,parent,nodenumber,nodes);
  477.  
  478.   if((b=AllocVec(bytes_block, bufmemtype))!=0) {
  479.     read2(block);
  480.     CopyMemQuick(buffer,b,bytes_block);
  481.  
  482.     if(isblockvalid(b,block,NODECONTAINER_ID)!=FALSE) {
  483.       if(b->nodenumber==nodenumber) {
  484.         if(nodes==0) {
  485.           nodes=b->nodes;
  486.         }
  487.  
  488.         if(b->nodes==nodes) {
  489.           if(nodes!=1) {
  490.             WORD maxnodes=(bytes_block-sizeof(struct fsNodeContainer))/4;
  491.             LONG nodes2=nodes/maxnodes;
  492.             WORD n;
  493.  
  494.             if(nodes2==0) {
  495.               nodes2=1;
  496.             }
  497.  
  498.             for(n=0; n<maxnodes; n++) {
  499.               if(b->node[n]!=0) {
  500.                 if(checknodecontainers2(b->node[n]>>shifts_block32, block, nodenumber, nodes2)==FALSE) {
  501.                   FreeVec(b);
  502.                   return(FALSE);
  503.                 }
  504.               }
  505.               nodenumber+=nodes;
  506.             }
  507.  
  508.             FreeVec(b);
  509.             return(TRUE);
  510.           }
  511.           else {
  512.             WORD maxnodes=(bytes_block-sizeof(struct fsNodeContainer))/sizeof(struct fsObjectNode);
  513.             WORD n;
  514.             struct fsObjectNode *on=(struct fsObjectNode *)b->node;
  515.  
  516.             for(n=0; n<maxnodes; n++) {
  517.               if(on->node.data!=0 && on->node.data!=-1) {
  518.                 if(checkobjectcontainerfornode(on->node.data,nodenumber+n)==FALSE) {
  519.                   FreeVec(b);
  520.                   return(FALSE);
  521.                 }
  522.               }
  523.  
  524.            /*
  525.               else if(on->node.data==0 && (on->next!=0 || on->hash16!=0)) {
  526.                 printf("NodeContainer at block %ld has a not fully cleared node.\n",block);
  527.                 FreeVec(b);
  528.                 return(FALSE);
  529.               }
  530.            */
  531.  
  532.               on++;
  533.             }
  534.  
  535.             FreeVec(b);
  536.             return(TRUE);
  537.           }
  538.         }
  539.         else {
  540.           printf("NodeContainer at block %ld has nodes %ld while it should be %ld.\n",block,b->nodes,nodes);
  541.         }
  542.       }
  543.       else {
  544.         printf("NodeContainer at block %ld has nodenumber %ld while it should be %ld.\n",block,b->nodenumber,nodenumber);
  545.       }
  546.     }
  547.  
  548.     FreeVec(b);
  549.   }
  550.   else {
  551.     printf("ERROR: Out of memory!\n");
  552.   }
  553.  
  554.   return(FALSE);
  555. }
  556.  
  557.  
  558. BOOL checknodecontainers(ULONG block) {
  559.   return(checknodecontainers2(block,0,1,0));
  560. }
  561.  
  562.  
  563.  
  564. UBYTE *mark(LONG offset, LONG blocks) {
  565.   LONG result;
  566.  
  567.   result=bmffo(bitmap, (blocks_total+31)>>5, offset);
  568.  
  569.   if(result!=-1 && result < offset+blocks) {
  570.     return(tostring("Block at offset %ld is already in use while marking %ld blocks from %ld.\n",result,blocks,offset));
  571.   }
  572.  
  573.   if((result=bmset(bitmap, (blocks_total+31)>>5, offset, blocks))!=blocks) {
  574.     return(tostring("Error while marking %ld blocks from %ld.  Could only mark %ld blocks.\n",blocks,offset,result));
  575.   }
  576.  
  577.   return(0);
  578. }
  579.  
  580.  
  581.  
  582. LONG findnode(BLCK nodeindex,UWORD nodesize,NODE nodeno,struct fsNode **returned_node) {
  583.   LONG errorcode;
  584.  
  585.   /* Finds a specific node by number.  It returns the cachebuffer which contains the fsNode
  586.      structure and a pointer to the fsNode structure directly. */
  587.  
  588.   while((errorcode=read2(nodeindex))==0) {
  589.     struct fsNodeContainer *nc=(struct fsNodeContainer *)buffer;
  590.  
  591.     if(nc->nodes==1) {
  592.       /* We've descended the tree to a leaf NodeContainer */
  593.  
  594.       *returned_node=(struct fsNode *)((UBYTE *)nc->node+nodesize*(nodeno-nc->nodenumber));
  595.  
  596.       return(0);
  597.     }
  598.     else {
  599.       UWORD containerentry=(nodeno-nc->nodenumber)/nc->nodes;
  600.  
  601.       nodeindex=nc->node[containerentry]>>shifts_block32;
  602.     }
  603.   }
  604.  
  605.   return(errorcode);
  606. }
  607.  
  608.  
  609.  
  610. BOOL checkobjectcontainers2(ULONG block, ULONG previous, ULONG parent) {
  611.   struct fsObjectContainer *oc;
  612.   UBYTE *str;
  613.  
  614.   if((oc=AllocVec(bytes_block, bufmemtype))!=0) {
  615.     do {
  616.       read2(block);
  617.       CopyMemQuick(buffer,oc,bytes_block);
  618.  
  619.       if(isblockvalid(oc,block,OBJECTCONTAINER_ID)!=FALSE) {
  620.         if(oc->previous==previous) {
  621.           if(oc->parent==parent) {
  622.             struct fsObject *o=oc->object;
  623.             struct fsObjectNode *node;
  624.             LONG errorcode;
  625.  
  626.             while(isobject(o,oc)!=FALSE) {
  627.  
  628.               if((errorcode=findnode(block_objectnodesbase, sizeof(struct fsObjectNode), o->objectnode , (struct fsNode **)&node))==0) {
  629.                 if(node->node.data==block) {
  630.                   if((o->bits & OTYPE_LINK)==0) {
  631.                     if((o->bits & OTYPE_DIR)!=0 && o->object.dir.firstdirblock!=0) {
  632.                       if(checkobjectcontainers2(o->object.dir.firstdirblock, 0, o->objectnode)==FALSE) {
  633.                         break;
  634.                       }
  635.                     }
  636.                     else if((o->bits & OTYPE_DIR)==0) {
  637.                       struct fsExtentBNode *ebn;
  638.                       ULONG next=o->object.file.data;
  639.                       ULONG prev=0;
  640.                       LONG errorcode;
  641.  
  642.                       while(next!=0) {
  643.                         if((errorcode=findbnode(block_extentbnoderoot, next, (struct BNode **)&ebn))!=0) {
  644.                           if(error("Errorcode %ld while locating BNode %ld of Object '%s' in ObjectContainer at block %ld.\n",errorcode,o->object.file.data,o->name,block)) {
  645.                             break;
  646.                           }
  647.                         }
  648.  
  649.                         if(ebn->key!=next) {
  650.                           if(error("Error in Object '%s' in ObjectContainer at block %ld:\nBNode %ld has incorrect key.  It is %ld while it should be %ld.\n",o->name,block,next,ebn->key,next)) {
  651.                             break;
  652.                           }
  653.                         }
  654.  
  655.                         if((prev!=0 && ebn->prev!=prev) || (prev==0 && ebn->prev!=(o->objectnode | 0x80000000))) {
  656.                           if(error("Error in Object '%s' in ObjectContainer at block %ld:\nBNode %ld has incorrect previous.  It is 0x%08lx.\n",o->name,block,next,ebn->prev)) {
  657.                             break;
  658.                           }
  659.                         }
  660.  
  661.                         if(ebn->blocks==0) {
  662.                           if(error("Error in Object '%s' in ObjectContainer at block %ld:\nBNode %ld has a zero block count!\n",o->name,block,next)) {
  663.                             break;
  664.                           }
  665.                         }
  666.  
  667.                         if((str=mark(ebn->key, ebn->blocks))!=0) {
  668.                           if(error("Error in Object '%s' in ObjectContainer at block %ld:\nBNode %ld points to space already in use:\n  %s",o->name,block,next,str)) {
  669.                             freestring(str);
  670.                             break;
  671.                           }
  672.                           freestring(str);
  673.                         }
  674.  
  675.                         prev=next;
  676.                         next=ebn->next;
  677.                       }
  678.  
  679.                       if(next!=0) {
  680.                         break;
  681.                       }
  682.                     }
  683.                   }
  684.                 }
  685.                 else {
  686.                   printf("Node %ld of Object in ObjectContainer at block %ld points to wrong block (%ld)\n",o->objectnode,block,node->node.data);
  687.                   break;
  688.                 }
  689.               }
  690.               else {
  691.                 printf("Error %ld occured while locating Node %ld of Object in ObjectContainer at block %ld.\n",errorcode,o->objectnode,block);
  692.                 break;
  693.               }
  694.  
  695.               o=nextobject(o);
  696.             }
  697.  
  698.             if(isobject(o,oc)!=FALSE) {
  699.               break;
  700.             }
  701.           }
  702.           else {
  703.             printf("ObjectContainer at block %ld has parent %ld while it should be %ld.\n",block,oc->parent,parent);
  704.             break;
  705.           }
  706.         }
  707.         else {
  708.           printf("ObjectContainer at block %ld has previous %ld while it should be %ld.\n",block,oc->previous,previous);
  709.           break;
  710.         }
  711.       }
  712.       else {
  713.         break;
  714.       }
  715.  
  716.       previous=block;
  717.       block=oc->next;
  718.     } while(block!=0);
  719.  
  720.     FreeVec(oc);
  721.  
  722.     if(block==0) {
  723.       return(TRUE);
  724.     }
  725.   }
  726.   else {
  727.     printf("ERROR: Out of memory!\n");
  728.   }
  729.  
  730.   return(FALSE);
  731. }
  732.  
  733.  
  734.  
  735. BOOL checkobjectcontainers(ULONG block) {
  736.   return(checkobjectcontainers2(block,0,0));
  737. }
  738.  
  739.  
  740.  
  741. void dumpblock(ULONG block, void *data, ULONG bytes) {
  742.   ULONG *d=(ULONG *)data;
  743.   UBYTE *d2=(UBYTE *)data;
  744.   UWORD off=0;
  745.   UBYTE s[40];
  746.  
  747.   if(bytes<bytes_block) {
  748.     printf("Dump of first %ld bytes of block %ld.\n",bytes,block);
  749.   }
  750.   else {
  751.     printf("Dump of block %ld.\n",block);
  752.   }
  753.  
  754.   while(bytes>0) {
  755.     WORD n;
  756.     UBYTE c;
  757.     UBYTE *s2;
  758.  
  759.     n=16;
  760.     s2=s;
  761.  
  762.     while(--n>=0) {
  763.       c=*d2++;
  764.  
  765.       if(c<32) {
  766.         c+=64;
  767.       }
  768.       if(c>=127 && c<=160) {
  769.         c='.';
  770.       }
  771.  
  772.       *s2++=c;
  773.     }
  774.     *s2=0;
  775.  
  776.     printf("0x%04lx: %08lx %08lx %08lx %08lx %s\n",off,d[0],d[1],d[2],d[3],s);
  777.  
  778.     bytes-=16;
  779.     d+=4;
  780.     off+=16;
  781.   }
  782. }
  783.  
  784.  
  785.  
  786. BOOL checkadminspacecontainers(ULONG block) {
  787.   struct fsAdminSpaceContainer *asc;
  788.  
  789.   if((asc=AllocVec(bytes_block, bufmemtype))!=0) {
  790.     ULONG previous=0;
  791.  
  792.     while(block!=0) {
  793.       read2(block);
  794.       CopyMemQuick(buffer,asc,bytes_block);
  795.  
  796.       if(isblockvalid(asc,block,ADMINSPACECONTAINER_ID)!=FALSE) {
  797.         if(asc->previous==previous) {
  798. //          if(asc->bits==32) {
  799.             struct fsAdminSpace *as=asc->adminspace;
  800.  
  801.             while((UBYTE *)as<((UBYTE *)asc+bytes_block) && as->space!=0) {
  802.               ULONG adminblock=as->space;
  803.               LONG bits=as->bits;
  804.               WORD n=32;
  805.               BYTE valid;
  806.               UBYTE *str;
  807.  
  808.               if((str=mark(adminblock,32))!=0) {
  809.                 if(error("AdminSpaceContainer at %ld occupies already used space:\n  %s",block,str)) {
  810.                   freestring(str);
  811.                   break;
  812.                 }
  813.                 freestring(str);
  814.               }
  815.  
  816.               while(--n>=0) {
  817.                 if(bits<0) {
  818.                   struct fsBlockHeader *bh=(struct fsBlockHeader *)buffer;
  819.  
  820.                   read2(adminblock);
  821.  
  822.                   valid=FALSE;
  823.                   if(checkchecksum((UBYTE *)bh)!=FALSE) {
  824.                     if(bh->id==ADMINSPACECONTAINER_ID || bh->id==OBJECTCONTAINER_ID || bh->id==HASHTABLE_ID || bh->id==NODECONTAINER_ID || bh->id==BNODECONTAINER_ID || bh->id==TRANSACTIONOK_ID || bh->id==SOFTLINK_ID) {
  825.                       if(bh->ownblock==adminblock) {
  826.                         valid=TRUE;
  827.                       }
  828.                     }
  829.                   }
  830.  
  831.                   if(valid==FALSE) {
  832.                     printf("Block %ld is not a valid admin block but it is marked in use in AdminSpaceContainer at %ld\n",adminblock,block);
  833.                     dumpblock(adminblock,buffer,64);
  834.                     break;
  835.                   }
  836.                 }
  837.                 bits<<=1;
  838.                 adminblock++;
  839.               }
  840.  
  841.               if(n>=0) {
  842.                 break;
  843.               }
  844.  
  845.               as++;
  846.             }
  847.  
  848.             if((UBYTE *)as<((UBYTE *)asc+bytes_block) && as->space!=0) {
  849.               break;
  850.             }
  851.  
  852. //          }
  853. //          else {
  854. //            printf("AdminSpaceContainer at block %ld hasn't got 32 blocks/entry (%ld)!\n",block,asc->bits);
  855. //            break;
  856. //          }
  857.         }
  858.         else {
  859.           printf("AdminSpaceContainer at block %ld has previous %ld while it should be %ld.\n",block,asc->previous,previous);
  860.           break;
  861.         }
  862.       }
  863.       else {
  864.         break;
  865.       }
  866.  
  867.       previous=block;
  868.       block=asc->next;
  869.     }
  870.  
  871.     FreeVec(asc);
  872.  
  873.     if(block==0) {
  874.       return(TRUE);
  875.     }
  876.   }
  877.   else {
  878.     printf("ERROR: Out of memory!\n");
  879.   }
  880.  
  881.   return(FALSE);
  882. }
  883.  
  884.  
  885.  
  886. void sfscheck(void) {
  887.   ULONG block_bitmapbase;
  888.   ULONG block_adminspacecontainer;
  889.  
  890.   printf("\n");
  891.   printf("Checking RootBlocks\n",0);
  892.  
  893.   read2(blocks_total-1);
  894.  
  895.   if((checkrootblock((struct fsRootBlock *)buffer,blocks_total-1))!=FALSE) {
  896.  
  897.     read2(0);
  898.  
  899.     if((checkrootblock((struct fsRootBlock *)buffer,0))!=FALSE) {
  900.       struct fsRootBlock *b=(struct fsRootBlock *)buffer;
  901.       UBYTE *str;
  902.  
  903.       printf("...okay\n");
  904.  
  905.       block_bitmapbase=b->bitmapbase;
  906.       block_root=b->rootobjectcontainer;
  907.       block_extentbnoderoot=b->extentbnoderoot;
  908.       block_adminspacecontainer=b->adminspacecontainer;
  909.       block_objectnodesbase=b->objectnoderoot;
  910.  
  911.       if((str=mark(block_bitmapbase,blocks_bitmap))!=0) {
  912.         Printf("Error while marking bitmap space:\n  %s",str);
  913.         freestring(str);
  914.       }
  915.  
  916.       printf("Checking AdminSpaceContainers at block %ld\n",block_adminspacecontainer);
  917.       if((checkadminspacecontainers(block_adminspacecontainer))!=FALSE) {
  918.         printf("...okay\n");
  919.  
  920.         printf("Checking NodeContainers at block %ld\n",block_objectnodesbase);
  921.         if((checknodecontainers(block_objectnodesbase))!=FALSE) {
  922.           printf("...okay\n");
  923.  
  924.           printf("Checking ObjectContainers at block %ld\n",block_root);
  925.           if((checkobjectcontainers(block_root))!=FALSE) {
  926.             printf("...okay\n");
  927.  
  928.             printf("Checking Bitmap at block %ld (%ld blocks, %ld bits/bitmap)\n",block_bitmapbase,blocks_bitmap,blocks_inbitmap);
  929.             if((checkbitmap(block_bitmapbase))!=FALSE) {
  930.               printf("...okay\n");
  931.  
  932.             }
  933.             else {
  934.               returncode=20;
  935.               printf("...damaged\n");
  936.             }
  937.           }
  938.           else {
  939.             returncode=20;
  940.             printf("...damaged\n");
  941.           }
  942.         }
  943.         else {
  944.           returncode=20;
  945.           printf("...damaged\n");
  946.         }
  947.       }
  948.       else {
  949.         returncode=20;
  950.         printf("...damaged\n");
  951.       }
  952.     }
  953.     else {
  954.       returncode=20;
  955.       printf("...damaged\n");
  956.     }
  957.   }
  958.   else {
  959.     returncode=20;
  960.     printf("...damaged\n");
  961.   }
  962.  
  963.  
  964.   if(errors!=0) {
  965.     returncode=20;
  966.   }
  967. }
  968.  
  969.  
  970.  
  971. struct BNode *searchforbnode(ULONG key,struct BTreeContainer *tc) {
  972.   struct BNode *tn;
  973.   WORD n=tc->nodecount-1;
  974.  
  975.   tn=(struct BNode *)((UBYTE *)tc->bnode+n*tc->nodesize);
  976.  
  977.   for(;;) {
  978.     if(n<=0 || key >= tn->key) {
  979.       return(tn);
  980.     }
  981.     tn=(struct BNode *)((UBYTE *)tn-tc->nodesize);
  982.     n--;
  983.   }
  984. }
  985.  
  986.  
  987.  
  988. LONG findbnode(BLCK rootblock,ULONG key,struct BNode **returned_bnode) {
  989.   LONG errorcode;
  990.  
  991.   while((errorcode=read2(rootblock))==0) {
  992.     struct fsBNodeContainer *bnc=(struct fsBNodeContainer *)buffer;
  993.     struct BTreeContainer *btc=&bnc->btc;
  994.  
  995.     *returned_bnode=searchforbnode(key,btc);
  996.     if(btc->isleaf==TRUE) {
  997.       break;
  998.     }
  999.     rootblock=(*returned_bnode)->data;
  1000.   }
  1001.  
  1002.   return(errorcode);
  1003. }
  1004.  
  1005.  
  1006.  
  1007. void freestring(UBYTE *str) {
  1008.   if(str!=emptystring) {
  1009.     FreeVec(str);
  1010.   }
  1011. }
  1012.  
  1013.  
  1014.  
  1015. UBYTE *tostring(UBYTE *fmt, ... ) {
  1016.   UBYTE *buf;
  1017.  
  1018.   if((buf=AllocVec(200,MEMF_CLEAR))!=0) {
  1019.     ULONG *args;
  1020.  
  1021.     args=(ULONG *)&fmt;
  1022.     args++;
  1023.  
  1024.     RawDoFmt(fmt,args,(void (*)())"\x16\xC0\x4E\x75",buf);
  1025.  
  1026.     return(buf);
  1027.   }
  1028.   else {
  1029.     return(emptystring);
  1030.   }
  1031. }
  1032.  
  1033.  
  1034.  
  1035. BOOL error(UBYTE *fmt, ... ) {
  1036.  
  1037.   VPrintf(fmt,((ULONG *)&fmt)+1);
  1038.  
  1039.   errors++;
  1040.  
  1041.   if(errors>maxerrors) {
  1042.     return(TRUE);
  1043.   }
  1044.  
  1045.   return(FALSE);
  1046. }
  1047.  
  1048.  
  1049. /* cachedio.o already implements this function, so the
  1050.    dummy function below is not needed.
  1051.  
  1052. LONG getbuffer(UBYTE **tempbuffer, ULONG *maxblocks) {
  1053.  
  1054.   /* Used by deviceio.o to get a piece of memory which it can
  1055.      use for buffering transfers when the Mask prevents a
  1056.      direct transfer.
  1057.  
  1058.      You must return 0, a pointer to the buffer and the number
  1059.      of blocks (each /bytes_block/ bytes in size) you allocated.
  1060.      For the purpose of SFScheck this function is probably never
  1061.      called since all our buffers are atleast LONG aligned and
  1062.      allocated with the correct bufmemtype. */
  1063.  
  1064.   return(ERROR_NO_FREE_STORE);
  1065. }
  1066.  
  1067. */
  1068.  
  1069.  
  1070. LONG req(UBYTE *fmt, UBYTE *gads, ... ) {
  1071.   ULONG args[5];
  1072.   ULONG *arg=args;
  1073.   UBYTE *fmt2;
  1074.   LONG gadget=0;
  1075.  
  1076.   /* Simple requester function which is called by deviceio.o
  1077.      for displaying low-level device errors and accesses outside
  1078.      the partition. */
  1079.  
  1080.   *arg=(ULONG)fmt;
  1081.  
  1082.   if((fmt2=AllocVec(strlen(fmt)+100,0))!=0) {
  1083.  
  1084.     RawDoFmt("%s",args,(void (*)())"\x16\xC0\x4E\x75",fmt2);
  1085.  
  1086.     {
  1087.       struct EasyStruct es;
  1088.       ULONG *args=(ULONG *)&gads;
  1089.  
  1090.       args++;
  1091.  
  1092.       es.es_StructSize=sizeof(struct EasyStruct);
  1093.       es.es_Flags=0;
  1094.       es.es_Title="SFScheck request";
  1095.       es.es_TextFormat=fmt2;
  1096.       es.es_GadgetFormat=gads;
  1097.  
  1098.       gadget=EasyRequestArgs(0,&es,0,args);
  1099.     }
  1100.  
  1101.     FreeVec(fmt2);
  1102.   }
  1103.  
  1104.   return(gadget);
  1105. }
  1106.  
  1107.  
  1108.  
  1109. void starttimeout(void) {
  1110.   /* Called by deviceio.o each time there is a physical
  1111.      disk access.  You can use this to start a timer and
  1112.      call motoroff() when the disk hasn't been accessed
  1113.      for a specific amount of time (SFS uses 1 second).
  1114.  
  1115.      SFScheck doesn't use this function. */
  1116. }
  1117.